home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 176-200 / disk_195 / microemacs / src.zoo / exec.c < prev    next >
C/C++ Source or Header  |  1989-03-23  |  29KB  |  1,343 lines

  1. /*    This file is for functions dealing with execution of
  2.     commands, command lines, buffers, files and startup files
  3.  
  4.     written 1986 by Daniel Lawrence                */
  5.  
  6. #include    <stdio.h>
  7. #include    "estruct.h"
  8. #include    "etype.h"
  9. #include    "edef.h"
  10. #include    "elang.h"
  11.  
  12. /* namedcmd:    execute a named command even if it is not bound */
  13.  
  14. PASCAL NEAR namedcmd(f, n)
  15.  
  16. int f, n;    /* command arguments [passed through to command executed] */
  17.  
  18. {
  19.     int (PASCAL NEAR *kfunc)();     /* ptr to the function to execute */
  20.     char buffer[NSTRING];        /* buffer to store function name */
  21.     int status;
  22.  
  23.     /* if we are non-interactive.... force the command interactivly */
  24.     if (clexec == TRUE) {
  25.         /* grab token and advance past */
  26.         execstr = token(execstr, buffer, NPAT);
  27.  
  28.         /* evaluate it */
  29.         strcpy(buffer, fixnull(getval(buffer)));
  30.         if (strcmp(buffer, errorm) == 0)
  31.             return(FALSE);
  32.  
  33.         /* and look it up */
  34.         if ((kfunc = fncmatch(buffer)) == NULL) {
  35.             mlwrite(TEXT16);
  36. /*                          "[No such Function]" */
  37.             return(FALSE);
  38.         }
  39.         
  40.         /* and execute it  INTERACTIVE */
  41.         clexec = FALSE;
  42.         status = (*kfunc)(f, n);    /* call the function */
  43.         clexec = TRUE;
  44.         return(status);
  45.     }
  46.  
  47.     /* prompt the user to type a named command */
  48.     /* and get the function name to execute */
  49.     kfunc = getname(": ");
  50.     if (kfunc == NULL) {
  51.         mlwrite(TEXT16);
  52. /*                      "[No such function]" */
  53.         return(FALSE);
  54.     }
  55.  
  56.     /* and then execute the command */
  57.     return((*kfunc)(f, n));
  58. }
  59.  
  60. /*    execcmd:    Execute a command line command to be typed in
  61.             by the user                    */
  62.  
  63. PASCAL NEAR execcmd(f, n)
  64.  
  65. int f, n;    /* default Flag and Numeric argument */
  66.  
  67. {
  68.     register int status;        /* status return */
  69.     char cmdstr[NSTRING];        /* string holding command to execute */
  70.  
  71.     /* get the line wanted */
  72.     if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
  73.         return(status);
  74.  
  75.     execlevel = 0;
  76.     return(docmd(cmdstr));
  77. }
  78.  
  79. /*    docmd:    take a passed string as a command line and translate
  80.         it to be executed as a command. This function will be
  81.         used by execute-command-line and by all source and
  82.         startup files. Lastflag/thisflag is also updated.
  83.  
  84.     format of the command line is:
  85.  
  86.         {# arg} <command-name> {<argument string(s)>}
  87.  
  88. */
  89.  
  90. PASCAL NEAR docmd(cline)
  91.  
  92. char *cline;    /* command line to execute */
  93.  
  94. {
  95.     register int f;        /* default argument flag */
  96.     register int n;        /* numeric repeat value */
  97.     int (PASCAL NEAR *fnc)();/* function to execute */
  98.     BUFFER *bp;        /* buffer to execute */
  99.     int status;        /* return status of function */
  100.     int oldcle;        /* old contents of clexec flag */
  101.     char *oldestr;        /* original exec string */
  102.     char tkn[NSTRING];    /* next token off of command line */
  103.         char bufn[NBUFN+2];    /* name of buffer to execute */
  104.  
  105.     /* if we are scanning and not executing..go back here */
  106.     if (execlevel)
  107.         return(TRUE);
  108.  
  109.     oldestr = execstr;    /* save last ptr to string to execute */
  110.     execstr = cline;    /* and set this one as current */
  111.  
  112.     /* first set up the default command values */
  113.     f = FALSE;
  114.     n = 1;
  115.     lastflag = thisflag;
  116.     thisflag = 0;
  117.  
  118.     if ((status = macarg(tkn)) != TRUE) {    /* and grab the first token */
  119.         execstr = oldestr;
  120.         return(status);
  121.     }
  122.  
  123.     /* process leadin argument */
  124.     if (gettyp(tkn) != TKCMD) {
  125.         f = TRUE;
  126.         strcpy(tkn, fixnull(getval(tkn)));
  127.         n = asc_int(tkn);
  128.  
  129.         /* and now get the command to execute */
  130.         if ((status = macarg(tkn)) != TRUE) {
  131.             execstr = oldestr;
  132.             return(status);
  133.         }
  134.     }
  135.  
  136.     /* and match the token to see if it exists */
  137.     if ((fnc = fncmatch(tkn)) == NULL) {
  138.  
  139.         /* construct the buffer name */
  140.         strcpy(bufn, "[");
  141.         strcat(bufn, tkn);
  142.         strcat(bufn, "]");
  143.  
  144.         /* find the pointer to that buffer */
  145.             if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  146.             mlwrite(TEXT16);
  147. /*                          "[No such Function]" */
  148.             execstr = oldestr;
  149.             return(FALSE);
  150.         }
  151.  
  152.         /* execute the buffer */
  153.         oldcle = clexec;    /* save old clexec flag */
  154.         clexec = TRUE;        /* in cline execution */
  155.         while (n-- > 0)
  156.             if ((status = dobuf(bp)) != TRUE)
  157.                 break;
  158.         cmdstatus = status;    /* save the status */
  159.         clexec = oldcle;    /* restore clexec flag */
  160.         execstr = oldestr;
  161.         return(status);
  162.     }
  163.     
  164.     /* save the arguments and go execute the command */
  165.     oldcle = clexec;        /* save old clexec flag */
  166.     clexec = TRUE;            /* in cline execution */
  167.     status = (*fnc)(f, n);        /* call the function */
  168.     cmdstatus = status;        /* save the status */
  169.     clexec = oldcle;        /* restore clexec flag */
  170.     execstr = oldestr;
  171.     return(status);
  172. }
  173.  
  174. /* token:    chop a token off a string
  175.         return a pointer past the token
  176. */
  177.  
  178. char *PASCAL NEAR token(src, tok, size)
  179.  
  180. char *src, *tok;    /* source string, destination token string */
  181. int size;        /* maximum size of token */
  182.  
  183. {
  184.     register int quotef;    /* is the current string quoted? */
  185.     register char c;    /* temporary character */
  186.  
  187.     /* first scan past any whitespace in the source string */
  188.     while (*src == ' ' || *src == '\t')
  189.         ++src;
  190.  
  191.     /* scan through the source string */
  192.     quotef = FALSE;
  193.     while (*src) {
  194.         /* process special characters */
  195.         if (*src == '~') {
  196.             ++src;
  197.             if (*src == 0)
  198.                 break;
  199.             switch (*src++) {
  200.                 case 'r':    c = 13; break;
  201.                 case 'n':    c = 13; break;
  202.                 case 'l':    c = 10; break;
  203.                 case 't':    c = 9;  break;
  204.                 case 'b':    c = 8;  break;
  205.                 case 'f':    c = 12; break;
  206.                 default:    c = *(src-1);
  207.             }
  208.             if (--size > 0) {
  209.                 *tok++ = c;
  210.             }
  211.         } else {
  212.             /* check for the end of the token */
  213.             if (quotef) {
  214.                 if (*src == '"')
  215.                     break;
  216.             } else {
  217.                 if (*src == ' ' || *src == '\t')
  218.                     break;
  219.             }
  220.  
  221.             /* set quote mode if quote found */
  222.             if (*src == '"')
  223.                 quotef = TRUE;
  224.  
  225.             /* record the character */
  226.             c = *src++;
  227.             if (--size > 0)
  228.                 *tok++ = c;
  229.         }
  230.     }
  231.  
  232.     /* terminate the token and exit */
  233.     if (*src)
  234.         ++src;
  235.     *tok = 0;
  236.     return(src);
  237. }
  238.  
  239. PASCAL NEAR macarg(tok)    /* get a macro line argument */
  240.  
  241. char *tok;    /* buffer to place argument */
  242.  
  243. {
  244.     int savcle;    /* buffer to store original clexec */
  245.     int status;
  246.  
  247.     savcle = clexec;    /* save execution mode */
  248.     clexec = TRUE;        /* get the argument */
  249.     status = nextarg("", tok, NSTRING, ctoec('\r'));
  250.     clexec = savcle;    /* restore execution mode */
  251.     return(status);
  252. }
  253.  
  254. /*    nextarg:    get the next argument    */
  255.  
  256. PASCAL NEAR nextarg(prompt, buffer, size, terminator)
  257.  
  258. char *prompt;        /* prompt to use if we must be interactive */
  259. char *buffer;        /* buffer to put token into */
  260. int size;        /* size of the buffer */
  261. int terminator;        /* terminating char to be used on interactive fetch */
  262.  
  263. {
  264.     register char *sp;    /* return pointer from getval() */
  265.  
  266.     /* if we are interactive, go get it! */
  267.     if (clexec == FALSE)
  268.         return(getstring(prompt, buffer, size, terminator));
  269.  
  270.     /* grab token and advance past */
  271.     execstr = token(execstr, buffer, size);
  272.  
  273.     /* evaluate it */
  274.     if ((sp = getval(buffer)) == NULL)
  275.         return(FALSE);
  276.     strcpy(buffer, sp);
  277.     return(TRUE);
  278. }
  279.  
  280. /*    storemac:    Set up a macro buffer and flag to store all
  281.             executed command lines there            */
  282.  
  283. PASCAL NEAR storemac(f, n)
  284.  
  285. int f;        /* default flag */
  286. int n;        /* macro number to use */
  287.  
  288. {
  289.     register struct BUFFER *bp;    /* pointer to macro buffer */
  290.     char bname[NBUFN];        /* name of buffer to use */
  291.  
  292.     /* must have a numeric argument to this function */
  293.     if (f == FALSE) {
  294.         mlwrite(TEXT111);
  295. /*                      "No macro specified" */
  296.         return(FALSE);
  297.     }
  298.  
  299.     /* range check the macro number */
  300.     if (n < 1 || n > 40) {
  301.         mlwrite(TEXT112);
  302. /*                      "Macro number out of range" */
  303.         return(FALSE);
  304.     }
  305.  
  306.     /* construct the macro buffer name */
  307.     strcpy(bname, "[Macro xx]");
  308.     bname[7] = '0' + (n / 10);
  309.     bname[8] = '0' + (n % 10);
  310.  
  311.     /* set up the new macro buffer */
  312.     if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  313.         mlwrite(TEXT113);
  314. /*                      "Can not create macro" */
  315.         return(FALSE);
  316.     }
  317.  
  318.     /* and make sure it is empty */
  319.     bclear(bp);
  320.  
  321.     /* and set the macro store pointers to it */
  322.     mstore = TRUE;
  323.     bstore = bp;
  324.     return(TRUE);
  325. }
  326.  
  327. #if    PROC
  328. /*    storeproc:    Set up a procedure buffer and flag to store all
  329.             executed command lines there            */
  330.  
  331. PASCAL NEAR storeproc(f, n)
  332.  
  333. int f;        /* default flag */
  334. int n;        /* macro number to use */
  335.  
  336. {
  337.     register struct BUFFER *bp;    /* pointer to macro buffer */
  338.     register int status;        /* return status */
  339.     char bname[NBUFN];        /* name of buffer to use */
  340.  
  341.     /* a numeric argument means its a numbered macro */
  342.     if (f == TRUE)
  343.         return(storemac(f, n));
  344.  
  345.     /* get the name of the procedure */
  346.         if ((status = mlreply(TEXT114, &bname[1], NBUFN-2)) != TRUE)
  347. /*                            "Procedure name: " */
  348.                 return(status);
  349.  
  350.     /* construct the macro buffer name */
  351.     bname[0] = '[';
  352.     strcat(bname, "]");
  353.  
  354.     /* set up the new macro buffer */
  355.     if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  356.         mlwrite(TEXT113);
  357. /*                      "Can not create macro" */
  358.         return(FALSE);
  359.     }
  360.  
  361.     /* and make sure it is empty */
  362.     bclear(bp);
  363.  
  364.     /* and set the macro store pointers to it */
  365.     mstore = TRUE;
  366.     bstore = bp;
  367.     return(TRUE);
  368. }
  369.  
  370. /*    execproc:    Execute a procedure                */
  371.  
  372. PASCAL NEAR execproc(f, n)
  373.  
  374. int f, n;    /* default flag and numeric arg */
  375.  
  376. {
  377.         register BUFFER *bp;        /* ptr to buffer to execute */
  378.         register int status;        /* status return */
  379.         char bufn[NBUFN+2];        /* name of buffer to execute */
  380.  
  381.     /* find out what buffer the user wants to execute */
  382.         if ((status = mlreply(TEXT115, &bufn[1], NBUFN)) != TRUE)
  383. /*                            "Execute procedure: " */
  384.                 return(status);
  385.  
  386.     /* construct the buffer name */
  387.     bufn[0] = '[';
  388.     strcat(bufn, "]");
  389.  
  390.     /* find the pointer to that buffer */
  391.         if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  392.         mlwrite(TEXT116);
  393. /*                      "No such procedure" */
  394.                 return(FALSE);
  395.         }
  396.  
  397.     /* and now execute it as asked */
  398.     while (n-- > 0)
  399.         if ((status = dobuf(bp)) != TRUE)
  400.             return(status);
  401.     return(TRUE);
  402. }
  403. #endif
  404.  
  405. /*    execbuf:    Execute the contents of a buffer of commands    */
  406.  
  407. PASCAL NEAR execbuf(f, n)
  408.  
  409. int f, n;    /* default flag and numeric arg */
  410.  
  411. {
  412.         register BUFFER *bp;        /* ptr to buffer to execute */
  413.         register int status;        /* status return */
  414.         char bufn[NSTRING];        /* name of buffer to execute */
  415.  
  416.     /* find out what buffer the user wants to execute */
  417.         if ((status = mlreply(TEXT117, bufn, NBUFN)) != TRUE)
  418. /*                            "Execute buffer: " */
  419.                 return(status);
  420.  
  421.     /* find the pointer to that buffer */
  422.         if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  423.         mlwrite(TEXT118);
  424. /*                      "No such buffer" */
  425.                 return(FALSE);
  426.         }
  427.  
  428.     /* and now execute it as asked */
  429.     while (n-- > 0)
  430.         if ((status = dobuf(bp)) != TRUE)
  431.             return(status);
  432.     return(TRUE);
  433. }
  434.  
  435. /*    dobuf:    execute the contents of the buffer pointed to
  436.         by the passed BP
  437.  
  438.     Directives start with a "!" and include:
  439.  
  440.     !endm        End a macro
  441.     !if (cond)    conditional execution
  442.     !else
  443.     !endif
  444.     !return        Return (terminating current macro)
  445.     !goto <label>    Jump to a label in the current macro
  446.     !force        Force macro to continue...even if command fails
  447.     !while (cond)    Execute a loop if the condition is true
  448.     !endwhile
  449.     
  450.     Line Labels begin with a "*" as the first nonblank char, like:
  451.  
  452.     *LBL01
  453. */
  454.  
  455. PASCAL NEAR dobuf(bp)
  456.  
  457. BUFFER *bp;    /* buffer to execute */
  458.  
  459. {
  460.         register int status;    /* status return */
  461.     register LINE *lp;    /* pointer to line to execute */
  462.     register LINE *hlp;    /* pointer to line header */
  463.     register LINE *glp;    /* line to goto */
  464.     LINE *mp;        /* Macro line storage temp */
  465.     int dirnum;        /* directive index */
  466.     int linlen;        /* length of line to execute */
  467.     int i;            /* index */
  468.     int force;        /* force TRUE result? */
  469.     WINDOW *wp;        /* ptr to windows to scan */
  470.     WHBLOCK *whlist;    /* ptr to !WHILE list */
  471.     WHBLOCK *scanner;    /* ptr during scan */
  472.     WHBLOCK *whtemp;    /* temporary ptr to a WHBLOCK */
  473.     char *einit;        /* initial value of eline */
  474.     char *eline;        /* text of line to execute */
  475.     char tkn[NSTRING];    /* buffer to evaluate an expresion in */
  476. #if    LOGFLG
  477.     FILE *fp;        /* file handle for log file */
  478. #endif
  479.  
  480.     /* clear IF level flags/while ptr */
  481.     execlevel = 0;
  482.     whlist = NULL;
  483.     scanner = NULL;
  484.  
  485.     /* scan the buffer to execute, building WHILE header blocks */
  486.     hlp = bp->b_linep;
  487.     lp = hlp->l_fp;
  488.     while (lp != hlp) {
  489.         /* scan the current line */
  490.         eline = lp->l_text;
  491.         i = lp->l_used;
  492.  
  493.         /* trim leading whitespace */
  494.         while (i-- > 0 && (*eline == ' ' || *eline == '\t'))
  495.             ++eline;
  496.  
  497.         /* if theres nothing here, don't bother */
  498.         if (i <= 0)
  499.             goto nxtscan;
  500.  
  501.         /* if is a while directive, make a block... */
  502.         if (eline[0] == '!' && eline[1] == 'w' && eline[2] == 'h') {
  503.             whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  504.             if (whtemp == NULL) {
  505. noram:                mlwrite(TEXT119);
  506. /*                                      "%%Out of memory during while scan" */
  507. failexit:            freewhile(scanner);
  508.                 freewhile(whlist);
  509.                 return(FALSE);
  510.             }
  511.             whtemp->w_begin = lp;
  512.             whtemp->w_type = BTWHILE;
  513.             whtemp->w_next = scanner;
  514.             scanner = whtemp;
  515.         }
  516.  
  517.         /* if is a BREAK directive, make a block... */
  518.         if (eline[0] == '!' && eline[1] == 'b' && eline[2] == 'r') {
  519.             if (scanner == NULL) {
  520.                 mlwrite(TEXT120);
  521. /*                                      "%%!BREAK outside of any !WHILE loop" */
  522.                 goto failexit;
  523.             }
  524.             whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  525.             if (whtemp == NULL)
  526.                 goto noram;
  527.             whtemp->w_begin = lp;
  528.             whtemp->w_type = BTBREAK;
  529.             whtemp->w_next = scanner;
  530.             scanner = whtemp;
  531.         }
  532.  
  533.         /* if it is an endwhile directive, record the spot... */
  534.         if (eline[0] == '!' && strncmp(&eline[1], "endw", 4) == 0) {
  535.             if (scanner == NULL) {
  536.                 mlwrite(TEXT121,
  537. /*                                      "%%!ENDWHILE with no preceding !WHILE in '%s'" */
  538.                     bp->b_bname);
  539.                 goto failexit;
  540.             }
  541.             /* move top records from the scanner list to the
  542.                whlist until we have moved all BREAK records
  543.                and one WHILE record */
  544.             do {
  545.                 scanner->w_end = lp;
  546.                 whtemp = whlist;
  547.                 whlist = scanner;
  548.                 scanner = scanner->w_next;
  549.                 whlist->w_next = whtemp;
  550.             } while (whlist->w_type == BTBREAK);
  551.         }
  552.  
  553. nxtscan:    /* on to the next line */
  554.         lp = lp->l_fp;
  555.     }
  556.  
  557.     /* while and endwhile should match! */
  558.     if (scanner != NULL) {
  559.         mlwrite(TEXT122,
  560. /*                      "%%!WHILE with no matching !ENDWHILE in '%s'" */
  561.             bp->b_bname);
  562.         goto failexit;
  563.     }
  564.  
  565.     /* let the first command inherit the flags from the last one..*/
  566.     thisflag = lastflag;
  567.  
  568.     /* starting at the beginning of the buffer */
  569.     hlp = bp->b_linep;
  570.     lp = hlp->l_fp;
  571.     while (lp != hlp && eexitflag == FALSE) {
  572.         /* allocate eline and copy macro line to it */
  573.         linlen = lp->l_used;
  574.         if ((einit = eline = malloc(linlen+1)) == NULL) {
  575.             mlwrite(TEXT123);
  576. /*                              "%%Out of Memory during macro execution" */
  577.             freewhile(whlist);
  578.             return(FALSE);
  579.         }
  580.         bytecopy(eline, lp->l_text, linlen);
  581.         eline[linlen] = 0;    /* make sure it ends */
  582.  
  583.         /* trim leading whitespace */
  584.         while (*eline == ' ' || *eline == '\t')
  585.             ++eline;
  586.  
  587.         /* dump comments and blank lines */
  588.         if (*eline == ';' || *eline == 0)
  589.             goto onward;
  590.  
  591. #if    LOGFLG
  592.         /* append the current command to the log file */
  593.         fp = fopen("emacs.log", "a");
  594.         strcpy(outline, eline);
  595.         fprintf(fp, "%s\n", outline);
  596.         fclose(fp);
  597. #endif
  598.     
  599. #if    DEBUGM
  600.         /* only do this if we are debugging */
  601.         if (macbug && !mstore && (execlevel == 0))
  602.             if (debug(bp, eline) == FALSE) {
  603.                 mlforce(TEXT54);
  604. /*                                      "[Macro aborted]" */
  605.                 freewhile(whlist);
  606.                 return(FALSE);
  607.             }
  608. #endif
  609.  
  610.         /* Parse directives here.... */
  611.         dirnum = -1;
  612.         if (*eline == '!') {
  613.             /* Find out which directive this is */
  614.             ++eline;
  615.             for (dirnum = 0; dirnum < NUMDIRS; dirnum++)
  616.                 if (strncmp(eline, dname[dirnum],
  617.                             strlen(dname[dirnum])) == 0)
  618.                     break;
  619.  
  620.             /* and bitch if it's illegal */
  621.             if (dirnum == NUMDIRS) {
  622.                 mlwrite(TEXT124);
  623. /*                                      "%%Unknown Directive" */
  624.                 freewhile(whlist);
  625.                 return(FALSE);
  626.             }
  627.  
  628.             /* service only the !ENDM macro here */
  629.             if (dirnum == DENDM) {
  630.                 mstore = FALSE;
  631.                 bstore = NULL;
  632.                 goto onward;
  633.             }
  634.  
  635.             /* restore the original eline....*/
  636.             --eline;
  637.         }
  638.  
  639.         /* if macro store is on, just salt this away */
  640.         if (mstore) {
  641.             /* allocate the space for the line */
  642.             linlen = strlen(eline);
  643.             if ((mp=lalloc(linlen)) == NULL) {
  644.                 mlwrite(TEXT125);
  645. /*                                      "Out of memory while storing macro" */
  646.                 return (FALSE);
  647.             }
  648.     
  649.             /* copy the text into the new line */
  650.             for (i=0; i<linlen; ++i)
  651.                 lputc(mp, i, eline[i]);
  652.     
  653.             /* attach the line to the end of the buffer */
  654.                    bstore->b_linep->l_bp->l_fp = mp;
  655.             mp->l_bp = bstore->b_linep->l_bp;
  656.             bstore->b_linep->l_bp = mp;
  657.             mp->l_fp = bstore->b_linep;
  658.             goto onward;
  659.         }
  660.     
  661.         force = FALSE;
  662.  
  663.         /* dump comments */
  664.         if (*eline == '*')
  665.             goto onward;
  666.  
  667.         /* now, execute directives */
  668.         if (dirnum != -1) {
  669.             /* skip past the directive */
  670.             while (*eline && *eline != ' ' && *eline != '\t')
  671.                 ++eline;
  672.             execstr = eline;
  673.  
  674.             switch (dirnum) {
  675.             case DIF:    /* IF directive */
  676.                 /* grab the value of the logical exp */
  677.                 if (execlevel == 0) {
  678.                     if (macarg(tkn) != TRUE)
  679.                         goto eexec;
  680.                     if (stol(tkn) == FALSE)
  681.                         ++execlevel;
  682.                 } else
  683.                     ++execlevel;
  684.                 goto onward;
  685.  
  686.             case DWHILE:    /* WHILE directive */
  687.                 /* grab the value of the logical exp */
  688.                 if (execlevel == 0) {
  689.                     if (macarg(tkn) != TRUE)
  690.                         goto eexec;
  691.                     if (stol(tkn) == TRUE)
  692.                         goto onward;
  693.                 }
  694.                 /* drop down and act just like !BREAK */
  695.  
  696.             case DBREAK:    /* BREAK directive */
  697.                 if (dirnum == DBREAK && execlevel)
  698.                     goto onward;
  699.  
  700.                 /* jump down to the endwhile */
  701.                 /* find the right while loop */
  702.                 whtemp = whlist;
  703.                 while (whtemp) {
  704.                     if (whtemp->w_begin == lp)
  705.                         break;
  706.                     whtemp = whtemp->w_next;
  707.                 }
  708.             
  709.                 if (whtemp == NULL) {
  710.                     mlwrite(TEXT126);
  711. /*                                              "%%Internal While loop error" */
  712.                     freewhile(whlist);
  713.                     return(FALSE);
  714.                 }
  715.             
  716.                 /* reset the line pointer back.. */
  717.                 lp = whtemp->w_end;
  718.                 goto onward;
  719.  
  720.             case DELSE:    /* ELSE directive */
  721.                 if (execlevel == 1)
  722.                     --execlevel;
  723.                 else if (execlevel == 0 )
  724.                     ++execlevel;
  725.                 goto onward;
  726.  
  727.             case DENDIF:    /* ENDIF directive */
  728.                 if (execlevel)
  729.                     --execlevel;
  730.                 goto onward;
  731.  
  732.             case DGOTO:    /* GOTO directive */
  733.                 /* .....only if we are currently executing */
  734.                 if (execlevel == 0) {
  735.  
  736.                     /* grab label to jump to */
  737.                     eline = token(eline, golabel, NPAT);
  738.                     linlen = strlen(golabel);
  739.                     glp = hlp->l_fp;
  740.                     while (glp != hlp) {
  741.                         if (*glp->l_text == '*' &&
  742.                             (strncmp(&glp->l_text[1], golabel,
  743.                                     linlen) == 0)) {
  744.                             lp = glp;
  745.                             goto onward;
  746.                         }
  747.                         glp = glp->l_fp;
  748.                     }
  749.                     mlwrite(TEXT127);
  750. /*                                              "%%No such label" */
  751.                     freewhile(whlist);
  752.                     return(FALSE);
  753.                 }
  754.                 goto onward;
  755.     
  756.             case DRETURN:    /* RETURN directive */
  757.                 if (execlevel == 0)
  758.                     goto eexec;
  759.                 goto onward;
  760.  
  761.             case DENDWHILE:    /* ENDWHILE directive */
  762.                 if (execlevel) {
  763.                     --execlevel;
  764.                     goto onward;
  765.                 } else {
  766.                     /* find the right while loop */
  767.                     whtemp = whlist;
  768.                     while (whtemp) {
  769.                         if (whtemp->w_type == BTWHILE &&
  770.                             whtemp->w_end == lp)
  771.                             break;
  772.                         whtemp = whtemp->w_next;
  773.                     }
  774.         
  775.                     if (whtemp == NULL) {
  776.                         mlwrite(TEXT126);
  777. /*                                                      "%%Internal While loop error" */
  778.                         freewhile(whlist);
  779.                         return(FALSE);
  780.                     }
  781.         
  782.                     /* reset the line pointer back.. */
  783.                     lp = whtemp->w_begin->l_bp;
  784.                     goto onward;
  785.                 }
  786.  
  787.             case DFORCE:    /* FORCE directive */
  788.                 force = TRUE;
  789.  
  790.             }
  791.         }
  792.  
  793.         /* execute the statement */
  794.         status = docmd(eline);
  795.         if (force)        /* force the status */
  796.             status = TRUE;
  797.  
  798.         /* check for a command error */
  799.         if (status != TRUE) {
  800.             /* look if buffer is showing */
  801.             wp = wheadp;
  802.             while (wp != NULL) {
  803.                 if (wp->w_bufp == bp) {
  804.                     /* and point it */
  805.                     wp->w_dotp = lp;
  806.                     wp->w_doto = 0;
  807.                     wp->w_flag |= WFHARD;
  808.                 }
  809.                 wp = wp->w_wndp;
  810.             }
  811.             /* in any case set the buffer . */
  812.             bp->b_dotp = lp;
  813.             bp->b_doto = 0;
  814.             free(einit);
  815.             execlevel = 0;
  816.             freewhile(whlist);
  817.             return(status);
  818.         }
  819.  
  820. onward:        /* on to the next line */
  821.         free(einit);
  822.         lp = lp->l_fp;
  823.     }
  824.  
  825. eexec:    /* exit the current function */
  826.     execlevel = 0;
  827.     freewhile(whlist);
  828.         return(TRUE);
  829. }
  830.  
  831. #if    DEBUGM
  832. /*        Interactive debugger
  833.  
  834.         if $debug == TRUE, The interactive debugger is invoked
  835.         commands are listed out with the ? key            */
  836.  
  837. PASCAL NEAR debug(bp, eline)
  838.  
  839. BUFFER *bp;    /* buffer to execute */
  840. char *eline;    /* text of line to debug */
  841.  
  842. {
  843.     register int oldcmd;        /* original command display flag */
  844.     register int oldinp;        /* original connamd input flag */
  845.     register int oldstatus;        /* status of last command */
  846.     register int c;            /* temp character */
  847.     register KEYTAB *key;        /* ptr to a key entry */
  848.     static char track[NSTRING] = "";/* expression to track value of */
  849.     char temp[NSTRING];        /* command or expression */
  850.  
  851. dbuild:    /* Build the information line to be presented to the user */
  852.  
  853.     strcpy(outline, "<<<");
  854.  
  855.     /* display the tracked expression */
  856.     if (track[0] != 0) {
  857.         oldstatus = cmdstatus;
  858.         docmd(track);
  859.         cmdstatus = oldstatus;
  860.         strcat(outline, "[=");
  861.         strcat(outline, gtusr("track"));
  862.         strcat(outline, "]");
  863.     }
  864.  
  865.     /* debug macro name */
  866.     strcat(outline, bp->b_bname);
  867.     strcat(outline, ":");
  868.  
  869.     /* and lastly the line */
  870.     strcat(outline, eline);
  871.     strcat(outline, ">>>");
  872.  
  873.     /* expand the %'s so mlwrite() won't interpret them */
  874.     makelit(outline);
  875.  
  876.     /* write out the debug line */
  877. dinput:    outline[term.t_ncol - 1] = 0;
  878.     mlforce(outline);
  879.     update(TRUE);
  880.  
  881.     /* and get the keystroke */
  882.     c = getkey();
  883.  
  884.     /* META key turns off debugging */
  885.     key = getbind(c);
  886.     if (key && key->k_ptr.fp == meta)
  887.         macbug = FALSE;
  888.  
  889.     else if (c == abortc) {
  890.         return(FALSE);
  891.  
  892.     } else switch (c) {
  893.  
  894.         case '?': /* list commands */
  895.             strcpy(outline, TEXT128);
  896. /*"(e)val exp, (c/x)ommand, (t)rack exp, (^G)abort, <SP>exec, <META> stop debug"*/
  897.             goto dinput;
  898.  
  899.         case 'c': /* execute statement */
  900.             oldcmd = discmd;
  901.             discmd = TRUE;
  902.             oldinp = disinp;
  903.             disinp = TRUE;
  904.             execcmd(FALSE, 1);
  905.             discmd = oldcmd;
  906.             disinp = oldinp;
  907.             goto dbuild;
  908.  
  909.         case 'x': /* execute extended command */
  910.             oldcmd = discmd;
  911.             discmd = TRUE;
  912.             oldinp = disinp;
  913.             disinp = TRUE;
  914.             oldstatus = cmdstatus;
  915.             namedcmd(FALSE, 1);
  916.             cmdstatus = oldstatus;
  917.             discmd = oldcmd;
  918.             disinp = oldinp;
  919.             goto dbuild;
  920.  
  921.         case 'e': /* evaluate expresion */
  922.             strcpy(temp, "set %track ");
  923.             oldcmd = discmd;
  924.             discmd = TRUE;
  925.             oldinp = disinp;
  926.             disinp = TRUE;
  927.             getstring("Exp: ", &temp[11], NSTRING, ctoec('\r'));
  928.             discmd = oldcmd;
  929.             disinp = oldinp;
  930.             oldstatus = cmdstatus;
  931.             docmd(temp);
  932.             cmdstatus = oldstatus;
  933.             strcpy(temp, " = [");
  934.             strcat(temp, gtusr("track"));
  935.             strcat(temp, "]");
  936.             mlforce(temp);
  937.             c = getkey();
  938.             goto dinput;
  939.  
  940.         case 't': /* track expresion */
  941.             oldcmd = discmd;
  942.             discmd = TRUE;
  943.             oldinp = disinp;
  944.             disinp = TRUE;
  945.             getstring("Exp: ", temp, NSTRING, ctoec('\r'));
  946.             discmd = oldcmd;
  947.             disinp = oldinp;
  948.             strcpy(track, "set %track ");
  949.             strcat(track, temp);
  950.             goto dbuild;
  951.  
  952.         case ' ': /* execute a statement */
  953.             break;
  954.  
  955.         default: /* illegal command */
  956.             TTbeep();
  957.             goto dbuild;
  958.     }
  959.     return(TRUE);
  960. }
  961. #endif
  962.  
  963. PASCAL NEAR makelit(s)        /* expand all "%" to "%%" */
  964.  
  965. char *s;    /* string to expand */
  966.  
  967. {
  968.     register char *sp;    /* temp for expanding string */
  969.     register char *ep;    /* ptr to end of string to expand */
  970.  
  971.     sp = s;
  972.     while (*sp)
  973.     if (*sp++ == '%') {
  974.         /* advance to the end */
  975.         ep = --sp;
  976.         while (*ep++)
  977.             ;
  978.         /* null terminate the string one out */
  979.         *(ep + 1) = 0;
  980.         /* copy backwards */
  981.         while(ep-- > sp)
  982.             *(ep + 1) = *ep;
  983.  
  984.         /* and advance sp past the new % */
  985.         sp += 2;                    
  986.     }
  987. }
  988.  
  989. PASCAL NEAR freewhile(wp)    /* free a list of while block pointers */
  990.  
  991. WHBLOCK *wp;    /* head of structure to free */
  992.  
  993. {
  994.     if (wp != NULL)
  995.     {
  996.         freewhile(wp->w_next);
  997.         free(wp);
  998.     }
  999. }
  1000.  
  1001. PASCAL NEAR execfile(f, n)    /* execute a series of commands in a file */
  1002.  
  1003. int f, n;    /* default flag and numeric arg to pass on to file */
  1004.  
  1005. {
  1006.     register int status;    /* return status of name query */
  1007.     char fname[NSTRING];    /* name of file to execute */
  1008.     char *fspec;        /* full file spec */
  1009.  
  1010.     if ((status = mlreply(TEXT129, fname, NSTRING -1)) != TRUE)
  1011. /*                            "File to execute: " */
  1012.         return(status);
  1013.  
  1014.     /* look up the path for the file */
  1015.     fspec = flook(fname, TRUE);
  1016.  
  1017.     /* if it isn't around */
  1018.     if (fspec == NULL) {
  1019.         /* complain if we are interactive */
  1020.         if (clexec == FALSE)
  1021.             mlwrite(TEXT214, fname);
  1022. /*                    "%%No such file as %s" */
  1023.         return(FALSE);
  1024.     }
  1025.  
  1026.     /* otherwise, execute it */
  1027.     while (n-- > 0)
  1028.         if ((status=dofile(fspec)) != TRUE)
  1029.             return(status);
  1030.  
  1031.     return(TRUE);
  1032. }
  1033.  
  1034. /*    dofile:    yank a file into a buffer and execute it
  1035.         if there are no errors, delete the buffer on exit */
  1036.  
  1037. PASCAL NEAR dofile(fname)
  1038.  
  1039. char *fname;    /* file name to execute */
  1040.  
  1041. {
  1042.     register BUFFER *bp;    /* buffer to place file to exeute */
  1043.     register BUFFER *cb;    /* temp to hold current buf while we read */
  1044.     register int status;    /* results of various calls */
  1045.     char bname[NBUFN];    /* name of buffer */
  1046.  
  1047.     makename(bname, fname);        /* derive the name of the buffer */
  1048.     unqname(bname);            /* make sure we don't stomp things */
  1049.     if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
  1050.         return(FALSE);
  1051.  
  1052.     bp->b_mode = MDVIEW;    /* mark the buffer as read only */
  1053.     cb = curbp;        /* save the old buffer */
  1054.     curbp = bp;        /* make this one current */
  1055.     /* and try to read in the file to execute */
  1056.     if ((status = readin(fname, FALSE)) != TRUE) {
  1057.         curbp = cb;    /* restore the current buffer */
  1058.         return(status);
  1059.     }
  1060.  
  1061.     /* go execute it! */
  1062.     curbp = cb;        /* restore the current buffer */
  1063.     if ((status = dobuf(bp)) != TRUE)
  1064.         return(status);
  1065.  
  1066.     /* if not displayed, remove the now unneeded buffer and exit */
  1067.     if (bp->b_nwnd == 0)
  1068.         zotbuf(bp);
  1069.     return(TRUE);
  1070. }
  1071.  
  1072. /*    cbuf:    Execute the contents of a numbered buffer    */
  1073.  
  1074. PASCAL NEAR cbuf(f, n, bufnum)
  1075.  
  1076. int f, n;    /* default flag and numeric arg */
  1077. int bufnum;    /* number of buffer to execute */
  1078.  
  1079. {
  1080.         register BUFFER *bp;        /* ptr to buffer to execute */
  1081.         register int status;        /* status return */
  1082.     static char bufname[] = "[Macro xx]";
  1083.  
  1084.     /* make the buffer name */
  1085.     bufname[7] = '0' + (bufnum / 10);
  1086.     bufname[8] = '0' + (bufnum % 10);
  1087.  
  1088.     /* find the pointer to that buffer */
  1089.         if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
  1090.             mlwrite(TEXT130);
  1091. /*                      "Macro not defined" */
  1092.                 return(FALSE);
  1093.         }
  1094.  
  1095.     /* and now execute it as asked */
  1096.     while (n-- > 0)
  1097.         if ((status = dobuf(bp)) != TRUE)
  1098.             return(status);
  1099.     return(TRUE);
  1100. }
  1101.  
  1102. PASCAL NEAR cbuf1(f, n)
  1103.  
  1104. {
  1105.     return(cbuf(f, n, 1));
  1106. }
  1107.  
  1108. PASCAL NEAR cbuf2(f, n)
  1109.  
  1110. {
  1111.     return(cbuf(f, n, 2));
  1112. }
  1113.  
  1114. PASCAL NEAR cbuf3(f, n)
  1115.  
  1116. {
  1117.     return(cbuf(f, n, 3));
  1118. }
  1119.  
  1120. PASCAL NEAR cbuf4(f, n)
  1121.  
  1122. {
  1123.     return(cbuf(f, n, 4));
  1124. }
  1125.  
  1126. PASCAL NEAR cbuf5(f, n)
  1127.  
  1128. {
  1129.     return(cbuf(f, n, 5));
  1130. }
  1131.  
  1132. PASCAL NEAR cbuf6(f, n)
  1133.  
  1134. {
  1135.     return(cbuf(f, n, 6));
  1136. }
  1137.  
  1138. PASCAL NEAR cbuf7(f, n)
  1139.  
  1140. {
  1141.     return(cbuf(f, n, 7));
  1142. }
  1143.  
  1144. PASCAL NEAR cbuf8(f, n)
  1145.  
  1146. {
  1147.     return(cbuf(f, n, 8));
  1148. }
  1149.  
  1150. PASCAL NEAR cbuf9(f, n)
  1151.  
  1152. {
  1153.     return(cbuf(f, n, 9));
  1154. }
  1155.  
  1156. PASCAL NEAR cbuf10(f, n)
  1157.  
  1158. {
  1159.     return(cbuf(f, n, 10));
  1160. }
  1161.  
  1162. PASCAL NEAR cbuf11(f, n)
  1163.  
  1164. {
  1165.     return(cbuf(f, n, 11));
  1166. }
  1167.  
  1168. PASCAL NEAR cbuf12(f, n)
  1169.  
  1170. {
  1171.     return(cbuf(f, n, 12));
  1172. }
  1173.  
  1174. PASCAL NEAR cbuf13(f, n)
  1175.  
  1176. {
  1177.     return(cbuf(f, n, 13));
  1178. }
  1179.  
  1180. PASCAL NEAR cbuf14(f, n)
  1181.  
  1182. {
  1183.     return(cbuf(f, n, 14));
  1184. }
  1185.  
  1186. PASCAL NEAR cbuf15(f, n)
  1187.  
  1188. {
  1189.     return(cbuf(f, n, 15));
  1190. }
  1191.  
  1192. PASCAL NEAR cbuf16(f, n)
  1193.  
  1194. {
  1195.     return(cbuf(f, n, 16));
  1196. }
  1197.  
  1198. PASCAL NEAR cbuf17(f, n)
  1199.  
  1200. {
  1201.     return(cbuf(f, n, 17));
  1202. }
  1203.  
  1204. PASCAL NEAR cbuf18(f, n)
  1205.  
  1206. {
  1207.     return(cbuf(f, n, 18));
  1208. }
  1209.  
  1210. PASCAL NEAR cbuf19(f, n)
  1211.  
  1212. {
  1213.     return(cbuf(f, n, 19));
  1214. }
  1215.  
  1216. PASCAL NEAR cbuf20(f, n)
  1217.  
  1218. {
  1219.     return(cbuf(f, n, 20));
  1220. }
  1221.  
  1222. PASCAL NEAR cbuf21(f, n)
  1223.  
  1224. {
  1225.     return(cbuf(f, n, 21));
  1226. }
  1227.  
  1228. PASCAL NEAR cbuf22(f, n)
  1229.  
  1230. {
  1231.     return(cbuf(f, n, 22));
  1232. }
  1233.  
  1234. PASCAL NEAR cbuf23(f, n)
  1235.  
  1236. {
  1237.     return(cbuf(f, n, 23));
  1238. }
  1239.  
  1240. PASCAL NEAR cbuf24(f, n)
  1241.  
  1242. {
  1243.     return(cbuf(f, n, 24));
  1244. }
  1245.  
  1246. PASCAL NEAR cbuf25(f, n)
  1247.  
  1248. {
  1249.     return(cbuf(f, n, 25));
  1250. }
  1251.  
  1252. PASCAL NEAR cbuf26(f, n)
  1253.  
  1254. {
  1255.     return(cbuf(f, n, 26));
  1256. }
  1257.  
  1258. PASCAL NEAR cbuf27(f, n)
  1259.  
  1260. {
  1261.     return(cbuf(f, n, 27));
  1262. }
  1263.  
  1264. PASCAL NEAR cbuf28(f, n)
  1265.  
  1266. {
  1267.     return(cbuf(f, n, 28));
  1268. }
  1269.  
  1270. PASCAL NEAR cbuf29(f, n)
  1271.  
  1272. {
  1273.     return(cbuf(f, n, 29));
  1274. }
  1275.  
  1276. PASCAL NEAR cbuf30(f, n)
  1277.  
  1278. {
  1279.     return(cbuf(f, n, 30));
  1280. }
  1281.  
  1282. PASCAL NEAR cbuf31(f, n)
  1283.  
  1284. {
  1285.     return(cbuf(f, n, 31));
  1286. }
  1287.  
  1288. PASCAL NEAR cbuf32(f, n)
  1289.  
  1290. {
  1291.     return(cbuf(f, n, 32));
  1292. }
  1293.  
  1294. PASCAL NEAR cbuf33(f, n)
  1295.  
  1296. {
  1297.     return(cbuf(f, n, 33));
  1298. }
  1299.  
  1300. PASCAL NEAR cbuf34(f, n)
  1301.  
  1302. {
  1303.     return(cbuf(f, n, 34));
  1304. }
  1305.  
  1306. PASCAL NEAR cbuf35(f, n)
  1307.  
  1308. {
  1309.     return(cbuf(f, n, 35));
  1310. }
  1311.  
  1312. PASCAL NEAR cbuf36(f, n)
  1313.  
  1314. {
  1315.     return(cbuf(f, n, 36));
  1316. }
  1317.  
  1318. PASCAL NEAR cbuf37(f, n)
  1319.  
  1320. {
  1321.     return(cbuf(f, n, 37));
  1322. }
  1323.  
  1324. PASCAL NEAR cbuf38(f, n)
  1325.  
  1326. {
  1327.     return(cbuf(f, n, 38));
  1328. }
  1329.  
  1330. PASCAL NEAR cbuf39(f, n)
  1331.  
  1332. {
  1333.     return(cbuf(f, n, 39));
  1334. }
  1335.  
  1336. PASCAL NEAR cbuf40(f, n)
  1337.  
  1338. {
  1339.     return(cbuf(f, n, 40));
  1340. }
  1341.  
  1342.  
  1343.